#version 330

struct Material{
    float shininess;
    vec3 specularColor;
};
struct DirectionalLight{
    vec3 osDirection;
    vec3 ambientColor;
    vec3 diffuseColor;
} ;

uniform sampler2D diffuseMap;
uniform sampler2D normalMap;

//Shadow mapping
uniform sampler2D shadowMap;
uniform mat4 shadowMapMatrix[4];
uniform vec4 splitDistance; //Start distance of 3 shadow maps
in vec4 worldCoord;
in float zpos;


uniform Material material;
uniform DirectionalLight light;

//Per fragment input
in vec3 f_tsVertexToLight;
in vec3 f_tsHalfAngle;
in vec2 f_uv;

out vec4 fragColor;
void main (){
 

    // - Get the CSM slice number: 0 is the nearset and 3 the farest
    bvec4 zGreater = lessThan( splitDistance , vec4(zpos) );
    int sliceIndex= int(zGreater.y)+int(zGreater.z)+int(zGreater.w);
    
    // - Show which slice is used
    #ifdef debug_slice
    if( mod(gl_FragCoord.x,8)<1){
        vec3 colors[4]=vec3[4](vec3(.5,.0,.0),vec3(.0,.5,.0),vec3(.0,.0,.5),vec3(.0,.5,.5));
        fragColor.rgb=colors[sliceIndex];
        return;
    }
    #endif

    // - Get the mapping coordinate according to hte slice
    vec4 shadowCoord = shadowMapMatrix[sliceIndex] * worldCoord;


    
    // - I the maping coordinates are out of the FBO frame
    #ifdef detect_overflow
    if( (sliceIndex==0 && ( shadowCoord.x <.0 || shadowCoord.x>.5 || shadowCoord.y <.0 || shadowCoord.y>.5 )) ||
        (sliceIndex==1 && ( shadowCoord.x <.5 || shadowCoord.x>1. || shadowCoord.y <.0 || shadowCoord.y>.5 )) ||
        (sliceIndex==2 && ( shadowCoord.x <.0 || shadowCoord.x>.5 || shadowCoord.y <.5 || shadowCoord.y>1. )) ||
        (sliceIndex==3 && ( shadowCoord.x <.5 || shadowCoord.x>1. || shadowCoord.y <.5 || shadowCoord.y>1. )) )
    {
        fragColor=vec4(shadowCoord.x,shadowCoord.y,zpos/255.,1.);
        return;
    }
    #endif


    // - Check whenever the fragment is in the shadow
    float shadowDepth = texture2D(shadowMap,shadowCoord.xy).r;

    #ifdef debug_show_depth_clamp
    if( shadowDepth >= 1. )
    {
        fragColor=vec4(.7,.0,.0,1.);
        return;
    }if( shadowDepth <= 0. )
    {
        fragColor=vec4(.0,.0,.7,1.);
        return;
    }
    #endif


    bool enlighted = (shadowDepth > shadowCoord.z) ;
    vec3 materialDiffuseColor = texture(diffuseMap, f_uv).rgb;
    vec4 normalFrag= texture(normalMap, f_uv);
    float dustFactor=min(normalFrag.a*2. + 0.7 ,1);

    
    if(enlighted){
        // This part has been reached by a light beam
        vec3 tsNormal = 2. * normalFrag.xyz - 1.;
        #ifdef no_normal_map
        tsNormal =vec3(0,0,1);
        #endif

        vec3 norm_tsVertexToLight = normalize(f_tsVertexToLight);
        float diffuseFactor = max(0., dot(normalize(tsNormal), norm_tsVertexToLight) );

        float specularFactor=0;
        if(diffuseFactor>0.){
            vec3 norm_tsHalfAngle = normalize(f_tsHalfAngle);
            specularFactor= max(0., dot(tsNormal, norm_tsHalfAngle) );
            specularFactor*=specularFactor;
            specularFactor*=specularFactor;            
            specularFactor*=specularFactor;            
        }

        #ifdef debug_faceback        
        // DEBUG - A fragment that faceback the light is displayed as green
        else{
          
             fragColor=vec4(.2,1.,.2,1.);
            return;
        }
        #endif


        #ifdef no_diffuse_map
        materialDiffuseColor=vec3(1,1,1);
        #endif
        float dustFactor=min(normalFrag.a*2. + 0.7 ,1);



        fragColor.rgb =
        + materialDiffuseColor * ( diffuseFactor*light.diffuseColor + light.ambientColor ) * dustFactor
        + specularFactor * material.specularColor *2.;
        ;
    }
    else {
        fragColor.rgb =  materialDiffuseColor *  light.ambientColor * dustFactor;
    }

   
    fragColor.a=1;
}
